package com.winbomb.simulife.impl;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.util.Log;

import com.winbomb.simulife.World;
import com.winbomb.simulife.base.CardType;
import com.winbomb.simulife.base.ICard;
import com.winbomb.simulife.base.ICardManager;
import com.winbomb.simulife.impl.cards.AmuseCard;
import com.winbomb.simulife.impl.cards.LearningCard;
import com.winbomb.simulife.impl.cards.SimpleCard;
import com.winbomb.simulife.impl.cards.SportsCard;
import com.winbomb.simulife.impl.cards.TalentCard;
import com.winbomb.simulife.util.ProbInvalidException;
import com.winbomb.simulife.util.ProbUtil;

public class CardManager implements ICardManager {

	private static final String TAG = "CardManager";

	/** 卡片的数量 */
	private static final int CARD_COUNT = 8;
	private static int currMonth;
	private static CardManager instance = null;
	private static World world;

	/** 用于记录已经出国的牌 */
	private static List<short[]> cardsList = new ArrayList<short[]>();

	/** 所有定义的牌 */
	private ICard[] allCards;
	private static final String CONFIG_FILE_PATH = "/com/winbomb/simulife/impl/cards/config.xml";
	private static final String CLASS_NAME_PREFIX = "com.winbomb.simulife.impl.cards.";

	public CardManager(World paramWorld) {
		world = paramWorld;
		currMonth = world.getMonthCount();

		SAXParserFactory factory = SAXParserFactory.newInstance();
		try {
			SAXParser parser = factory.newSAXParser();
			InputStream fis = EventManager.class.getResourceAsStream(CONFIG_FILE_PATH);

			XMLContentHandler handler = new XMLContentHandler();
			parser.parse(fis, handler);

			CardElem[] cardElems = handler.getCards();

			allCards = parseCardElems(cardElems);

		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	private ICard[] parseCardElems(CardElem[] cardElems) {
		List<ICard> cardList = new ArrayList<ICard>();
		for (CardElem card : cardElems) {
			if (card == null) {
				continue;
			}

			String classFullName = CLASS_NAME_PREFIX + card.getClassName();
			Class<World> clazz;
			try {
				clazz = (Class<World>) Class.forName(classFullName);
				Constructor<World> constructor = clazz.getConstructor(World.class);
				ICard cardImpl = (ICard) constructor.newInstance(world);
				cardList.add(cardImpl);
			} catch (ClassNotFoundException e) {
				Log.w(TAG, "Could not found class: " + classFullName);
			} catch (NoSuchMethodException e) {
				Log.w(TAG, "Cound not find proper constructor while loading class: "
						+ classFullName);
			} catch (Exception ex) {
				Log.w(TAG, "Error occured while loading class: " + classFullName + " caused by "
						+ ex);
			}

		}

		return cardList.toArray(new ICard[cardList.size()]);
	}

	public synchronized static CardManager getInstance(World paramWorld) {
		if (instance == null) {
			instance = new CardManager(paramWorld);
		}
		return instance;
	}

	@Override
	public boolean contains(int monthId, int cardId) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int getCardCount(int monthId, int cardId) {

		short[] cards = getCardsByMonth(monthId);
		return countByCardId(cards, cardId);
	}

	@Override
	public int getCardCount(int monthId, CardType type) {

		short[] cards = getCardsByMonth(monthId);
		return countByCardType(cards, type);
	}

	@Override
	public int getCardCount(int begMonth, int endMonth, int cardId) {

		int total = 0;
		for (int i = begMonth; i <= endMonth; i++) {
			total += getCardCount(i, cardId);
		}
		return total;
	}

	@Override
	public int getCardCount(int begMonth, int endMonth, CardType type) {

		int total = 0;
		for (int i = begMonth; i <= endMonth; i++) {
			total += getCardCount(i, type);
		}
		return total;
	}

	private short[] getCardsByMonth(int monthId) throws InvalidParameterException {

		if (monthId < 0 || monthId >= cardsList.size()) {
			throw new InvalidParameterException("MonthId is invalid, monthId is " + monthId
					+ " , record size is " + cardsList.size());
		}

		return cardsList.get(monthId);
	}

	private int countByCardType(short[] cards, CardType type) {
		int count = 0;
		for (short id : cards) {
			if (type.isThisType(id)) {
				count++;
			}
		}
		return count;
	}

	private int countByCardId(short[] cards, int cardId) {
		int count = 0;
		for (short id : cards) {
			if (id == cardId) {
				count++;
			}
		}
		return count;
	}

	@Override
	public void step() {
		currMonth++;
		short[] cards = new short[10];
		cardsList.add(cards);
	}

	@Override
	public void record(ICard card) {
		short[] cards = cardsList.get(currMonth - 1);
		for (int i = 0; i < cards.length; i++) {
			if (cards[i] == 0) {
				cards[i] = card.getCardId();
				break;
			}
		}
	}

	@Override
	public ICard[] dealNewCards() {

		ICard[] cards = new ICard[CARD_COUNT];

		for (int i = 0; i < cards.length; i++) {
			cards[i] = getNextCard();
		}

		return cards;
	}

	/**
	 * 60% - Learning 20% - Sports 10% - Amuse 10% - Talent
	 * 
	 * @return
	 */
	private ICard getNextCard() {

		CardType type = getCardTypeByRate();

		if (type == CardType.LEARN) {

			// 从所有的学习类型的卡片中随机选一张
			return new LearningCard(world);

		} else if (type == CardType.SPORTS) {

			return new SportsCard(world);

		} else if (type == CardType.AMUSE) {

			return new AmuseCard(world);

		} else if (type == CardType.TALENT) {

			return new TalentCard(world);
		}

		return new SimpleCard(world);
	}

	private CardType getCardTypeByRate() {

		float[] probs = new float[] { 0.6f, 0.2f, 0.1f, 0.1f };
		CardType[] types = new CardType[] { CardType.LEARN, CardType.SPORTS, CardType.AMUSE,
				CardType.TALENT };
		try {
			int idx = ProbUtil.testProbs(probs);
			return types[idx];
		} catch (ProbInvalidException pe) {
			Log.w("CardManager", pe);
		}

		return CardType.UNKNOWN;
	}

	class XMLContentHandler extends DefaultHandler {

		private List<CardElem> cardList;
		private CardElem card;
		private String preTag;
		private static final String ELEM_CARD = "Card";
		private static final String ELEM_CLASS_NAME = "ClassName";
		private static final String ELEM_CARD_TYPE = "CardType";

		public CardElem[] getCards() {
			return cardList.toArray(new CardElem[cardList.size()]);
		}

		/**
		 * 要开始读取xml文件的时候调用的方法 初始化persons
		 */
		@Override
		public void startDocument() throws SAXException {
			cardList = new ArrayList<CardElem>();
		}

		/**
		 * sax 读取到文本节点的时候调用了这个方法
		 */
		@Override
		public void characters(char[] ch, int start, int length) throws SAXException {

			if (preTag != null && card != null) {
				String data = new String(ch, start, length);
				if (ELEM_CLASS_NAME.equals(preTag)) {
					card.setClassName(data);
				} else if (ELEM_CARD_TYPE.equals(preTag)) {
					int cardType = 0;
					try {
						cardType = Integer.parseInt(data);
					} catch (NumberFormatException ex) {
						Log.w(TAG, "");
					}
					card.setCardType(cardType);
				}
			}
		}

		/**
		 * sax 读取到元素节点的时候用到这个方法；
		 */
		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes)
				throws SAXException {
			if (ELEM_CARD.equals(localName)) {
				card = new CardElem();
			}
			preTag = localName;
		}

		/**
		 * 这个方法是每次遇到结束的标签都会执行的 并不是只遇到最后的结尾才调用
		 */

		@Override
		public void endElement(String uri, String localName, String name) throws SAXException {

			if (ELEM_CARD.equals(localName) && card != null) {
				cardList.add(card);
				card = null;
			}
			preTag = null;
		}
	}
}

class CardElem {

	private String className;
	private int cardType;

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public int getCardType() {
		return cardType;
	}

	public void setCardType(int cardType) {
		this.cardType = cardType;
	}
}
